"""before we do anything else, overwrite the pysqlite2 namespace"""
import os
import sys
import string
import simplejson as json
import geojson
from geojson.mapping import is_mapping, to_mapping
from types import NoneType
from bottle import route, run, debug, request, abort, default_app,static_file
import bottle
from Gzipper import Gzipper

import pyspatialite
sys.modules['pysqlite2'] = pyspatialite

from geosoup import SqlSoup,Session,GeoJsonEncoder

from shapely import wkb
import shapely
from geoalchemy import *
from sqlalchemy import * 
from sqlalchemy.orm import *

engine = create_engine('sqlite:///test.sqlite')
meta = MetaData(engine)
meta.reflect(bind=engine)
geokey = 'Geometry'
TABLE_PREFIX = 'pdx_'
BASE_PATH = reduce (lambda l,r: l + os.path.sep + r, os.path.dirname( os.path.realpath( __file__ ) ).split( os.path.sep )[:-1] ) + os.path.sep + 'pyod' + os.path.sep

binop_map = {
  'eq': '==',
  'ne': '!=',
  'gt': '>',
  'ge': '>=',
  'lt': '<',
  'le': '<='
}

entitysets = []
for table in reversed(meta.sorted_tables):
    if table.name.startswith(TABLE_PREFIX):
      entitysets.append(table.name)
      if not table.primary_key.columns:
        table = Table(table.name, meta, Column('ROWID', Integer, primary_key=True),useexisting=True)
        
soup = SqlSoup(meta)
session = soup.session
        
@route('/v1/',method='GET')
def ServiceRoot():
    return {'d':{'EntitySets':entitysets}}

def ConvertGeoColumns(d,defer=True):
  if geokey in d:
    b = wkb.loads(d[geokey].geom_wkb[:])
    del d[geokey]
    if not defer or isinstance(b,shapely.geometry.polygon.Polygon) \
      or isinstance(b,shapely.geometry.point.Point) \
      or isinstance(b,shapely.geometry.linestring.LineString):
      d['geo'] = json.loads(geojson.dumps(b))
    else:
      d['geo'] = { '__deferred': { 'uri': 'TYPE(PK)' } }
  if '_sa_instance_state' in d:
    del d['_sa_instance_state']
  return d

@route('/v1/:#(?P<collection>[a-zA-Z_]+)#',method='GET')
@route('/v1/:#(?P<collection>[a-zA-Z_]+)\((?P<key>[0-9]+)\)#',method='GET')
@route('/v1/:#(?P<collection>[a-zA-Z_]+)\((?P<key>[0-9]+)\)/(?P<property>[a-zA-Z_]+)#',method='GET')
@route('/v1/:#(?P<collection>[a-zA-Z_]+)\((?P<key>[0-9]+)\)/(?P<property>[a-zA-Z_]+)/(?P<v>\$value)#',method='GET')
def ResourcePath(collection,key = -1, property = None, v = None):
  _response = 'json'
  opts = { }
  if ('$top' in request.GET and '$limit' in request.GET):
    abort(400, "Must define only one of $top or $limit")
  if ('$skip' in request.GET and '$offset' in request.GET):
    abort(400, "Must define only one of $skip or $offset")
  _filter = request.GET.get('$filter', '').strip()
  _inlinecount = request.GET.get('$inlinecount', 'none').strip()
  _expand = request.GET.get('$expand','').strip()
  defer = False if _expand == 'true' else True
  for opt in ['orderby','top','skip','limit','offset']:
    try:
      i = int(request.GET["$" + opt])
      if i > 0:
        opts[opt] = i
    except:
      pass
   
  o = {'d':[]}
  if not collection in entitysets:
    abort(404, "That Entity does not exists")
  
  table = soup.entity(collection)
  if not key == -1 and not key == None:
    row = table.get(key)
    if type(row) == NoneType:
      abort(404,'Collection with that id does not exist')
    if not property == None:
      try:
        if property == 'geo':
          property = geokey
          defer=False
        td = {property : getattr(row,property)}
        o['d'] = ConvertGeoColumns(td,defer)
        if not v == None:
          return o['d'][property]
      except AttributeError:
        abort(404,'Collection does not have that Property')
    else:
      o['d'] = ConvertGeoColumns(row.__dict__)
  else:
    o['d'] = []
    if len(_filter) > 0:
      for k,v in binop_map:
        _filter = _filter.replace(' ' + k + ' ',v)
      print _filter
      table = table.filter(_filter)
    limit = opts['top'] if 'top' in opts else (opts['limit'] if 'limit' in opts else 50)
    limit = 50 if limit > 50 else limit
    offset = opts['skip'] if 'skip' in opts else (opts['offset'] if 'offset' in opts else 0)
    count = table.count()
    table = table.limit(limit)
    if offset > 0:
      table = table.offset(offset)
    rows = table.all()
    for row in rows:
      r = ConvertGeoColumns(row.__dict__,defer)
      o['d'].append(r)
  r = json.dumps(o,cls=GeoJsonEncoder)
  return r

@route('/index.html')
def index():
  return bottle.static_file('index.html',BASE_PATH)


bottle.debug(True)
if __name__ == '__main__':
  gapp = default_app()
#  gapp = Gzipper(gapp)
#  run(app=gapp,server=bottle.FapwsServer,reloader=True)
  run(app=gapp,reloader=True)

